<template>
  <div class="guagga scaner" ref="guaggaRef" id="my_result">
    <i class="close" @click="fullStop()"> </i>
    <div class="banner" v-if="showBanner">
      <svg-icon
        icon-class="closefull"
        class="cursor-pointer close_icon"
        @click="() => (showBanner = false)"
      />
      <p class="text">若当前浏览器无法扫码，请切换其他浏览器尝试</p>
    </div>
    <div class="cover">
      <p class="line"></p>
      <span class="square top left"></span>
      <span class="square top right"></span>
      <span class="square bottom right"></span>
      <span class="square bottom left"></span>
      <p class="tips">请将条形码放入框内</p>
    </div>
  </div>
</template>

<script setup lang="ts">
import Quagga from "quagga";
defineOptions({
  name: "BarCode",
  inheritAttrs: false,
});

// 捕获异常
interface ErrorProps {
  name?: string;
  message?: string;
}
// 条形码返回值
interface DetectedResult {
  codeResult?: {
    code: string;
  };
}

const emit = defineEmits(["close-scaner", "code-scanned", "error-captured"]);

const props = defineProps({
  // 使用后置相机
  useBackCamera: {
    type: Boolean,
    default: true,
  },
  /**
   * readers 解码的条形码类型的数组 ["code_128_reader"]
   * < 建议只写一种类型，以便更快扫码 >
   * code_128_reader（默认）
   * ean_reader
   * ean_8_reader
   * code_39_reader
   * code_39_vin_reader
   * codabar_reader
   * upc_reader
   * upc_e_reader
   *
   **/
  readers: {
    type: Array,
    default: () => ["code_128_reader", "ean_reader"],
  },
  streamType: {
    type: String,
    default: "LiveStream",
  },
});

const { readers, streamType, useBackCamera } = toRefs(props);
const showBanner = ref(true);

function qinit() {
  Quagga.init(
    {
      inputStream: {
        name: "Live",
        type: streamType.value, // ImageStream，VideoStream，或LiveStream（默认值）
        target: document.querySelector("#my_result"), // Or '#yourElement' (optional)
        constraints: {
          facingMode: useBackCamera ? "environment" : "user",
        },
      },
      decoder: {
        readers: readers.value,
        // 调试时开启
        // debug: {
        //   drawBoundingBox: true,
        //   showFrequency: true,
        //   drawScanline: true,
        //   showPattern: true,
        // },
        multiple: false,
      },
    },
    function (error: ErrorProps) {
      if (error) {
        emit("error-captured", error);
        console.dir(error);
        return;
      }
      Quagga.start();

      Quagga.onDetected(function (data: DetectedResult) {
        if (data?.codeResult?.code) {
          emit("code-scanned", data?.codeResult?.code);
          Quagga.stop();
        } else {
          ElMessage.error("未识别到条形码");
        }
      });
    }
  );
}
//停止扫描
function fullStop() {
  Quagga.stop();
  emit("close-scaner", false);
}

onMounted(() => {
  qinit();
});

onBeforeUnmount(() => {
  fullStop();
});
</script>

<style lang="scss" scoped>
:deep(video) {
  width: 100% !important;
  height: 100% !important;
}
.close {
  display: inline-block;
  height: 80px;
  width: 80px;
  background: url("@/assets/images/close.png") no-repeat center;
  background-size: auto 100%;
  position: absolute;
  color: #ffffff;
  left: 2px;
  top: 5px;
  z-index: 200;
}
.scaner {
  background: #000000;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  height: -webkit-calc(100%);
  height: -moz-calc(100%);
  height: -ms-calc(100%);
  height: -o-calc(100%);
  height: calc(100%);
}
.scaner .banner {
  width: 340px;
  position: absolute;
  top: 16px;
  left: 50%;
  margin-left: -170px;
  background: #e6a23c;
  border-radius: 8px;
  box-sizing: border-box;
  padding: 12px;
  opacity: 0.9;
  box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.2);
  color: #ffffff;
}
.scaner .banner .text {
  padding: 0;
  margin: 0;
  color: #ffffff;
  font-size: 12px;
  text-align: justify;
  text-align-last: left;
}
.scaner .banner .close_icon {
  display: inline-block;
  height: 20px !important;
  width: 20px !important;
  position: absolute;
  right: 10px;
  top: 10px;
}
.scaner .cover {
  height: 300px;
  width: 520px;
  position: absolute;
  top: 40%;
  left: 50%;
  -webkit-transform: translate(-50%, -50%);
  -moz-transform: translate(-50%, -50%);
  -ms-transform: translate(-50%, -50%);
  -o-transform: translate(-50%, -50%);
  transform: translate(-50%, -50%);
  /* border: 0.5px solid #999999; */
  z-index: 1111;
}
.scaner .cover .line {
  width: 300px;
  height: 1px;
  margin-left: 10px;
  background: #5f68e8;
  background: linear-gradient(
    to right,
    transparent,
    #5f68e8,
    #0165ff,
    #5f68e8,
    transparent
  );
  position: absolute;
  -webkit-animation: scan 1.75s infinite linear;
  -moz-animation: scan 1.75s infinite linear;
  -ms-animation: scan 1.75s infinite linear;
  -o-animation: scan 1.75s infinite linear;
  animation: scan 1.75s infinite linear;
  -webkit-animation-fill-mode: both;
  -moz-animation-fill-mode: both;
  -ms-animation-fill-mode: both;
  -o-animation-fill-mode: both;
  animation-fill-mode: both;
  border-radius: 1px;
}
.scaner .cover .square {
  display: inline-block;
  height: 20px;
  width: 20px;
  position: absolute;
}
.scaner .cover .square.top {
  top: 0;
  border-top: 1px solid #5f68e8;
}
.scaner .cover .square.left {
  left: 0;
  border-left: 1px solid #5f68e8;
}
.scaner .cover .square.bottom {
  bottom: 0;
  border-bottom: 1px solid #5f68e8;
}
.scaner .cover .square.right {
  right: 0;
  border-right: 1px solid #5f68e8;
}
.scaner .cover .tips {
  position: absolute;
  bottom: -70px;
  width: 100%;
  text-align: center;
  font-size: 13px;
  color: #ffffff;
  opacity: 0.8;
}
@-webkit-keyframes scan {
  0% {
    top: 0;
  }
  25% {
    top: 50px;
  }
  50% {
    top: 100px;
  }
  75% {
    top: 150px;
  }
  100% {
    top: 200px;
  }
}
@-moz-keyframes scan {
  0% {
    top: 0;
  }
  25% {
    top: 50px;
  }
  50% {
    top: 100px;
  }
  75% {
    top: 150px;
  }
  100% {
    top: 200px;
  }
}
@-o-keyframes scan {
  0% {
    top: 0;
  }
  25% {
    top: 50px;
  }
  50% {
    top: 100px;
  }
  75% {
    top: 150px;
  }
  100% {
    top: 200px;
  }
}
@keyframes scan {
  0% {
    top: 0;
  }
  25% {
    top: 50px;
  }
  50% {
    top: 100px;
  }
  75% {
    top: 150px;
  }
  100% {
    top: 200px;
  }
}
</style>
